/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2023. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */

/*!
 * @file ac780x_spi.c
 *
 * @brief This file provides spi integration functions.
 *
 */

/* ===========================================  Includes  =========================================== */
#include "ac780x_spi_reg.h"
#include "ac780x_dma_reg.h"

/* ============================================  Define  ============================================ */

/* ===========================================  Typedef  ============================================ */

/* ==========================================  Variables  =========================================== */
#ifdef SPI_USE_INTERRUPT_TRANSMIT
uint8_t *g_spiRxBuf[SPI_INDEX_MAX] = {NULL};            /*!< SPIx Rx buffer pointer */
const uint8_t *g_spiTxBuf[SPI_INDEX_MAX] = {NULL};      /*!< SPIx Tx buffer pointer */
uint32_t g_spiRxCount[SPI_INDEX_MAX] = {0U};            /*!< SPIx buffer receive counter */
uint32_t g_spiTxCount[SPI_INDEX_MAX] = {0U};            /*!< SPIx buffer transmit counter */
uint32_t g_spiBuffSize[SPI_INDEX_MAX] = {0U};           /*!< SPIx buffer size data */
uint32_t g_spiStatus[SPI_INDEX_MAX] = {0U};             /*!< SPIx interrupt tx/rx work status */
#endif /* SPI_USE_INTERRUPT_TRANSMIT */

/*!< SPI Interrupt callback */
static DeviceCallback_Type s_spiCallbackArray[SPI_INDEX_MAX] = {NULL};

const SPI_InfoType g_spiInfo[SPI_INSTANCE_MAX] =
{
    {SPI0, SPI0_IRQn, CLK_SPI0, SRST_SPI0},
    {SPI1, SPI1_IRQn, CLK_SPI1, SRST_SPI1},
};

/* ====================================  Functions declaration  ===================================== */
#ifdef SPI_USE_INTERRUPT_TRANSMIT
static void SPI_InitInterruptHandler(SPI_Type *SPIx);
static void SPI_InterruptHandler(SPI_Type *SPIx);
static void SPI_MasterInterruptHandler(SPI_Type *SPIx);
static void SPI_SlaveInterruptHandler(SPI_Type *SPIx);
#endif /* SPI_USE_INTERRUPT_TRANSMIT */

/* ======================================  Functions define  ======================================== */
/*!
 * @brief Initialize SPI module
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] config: SPI configuration structure pointer which contains the configuration
 *                    information for the specified SPI.
 * @return none
 */
void SPI_Init(SPI_Type *SPIx, const SPI_ConfigType *config)
{
    SPI_IndexType spiIndex = SPI_INDEX(SPIx);

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));
    DEVICE_ASSERT(IS_SPI_MODE(config->mode));
    DEVICE_ASSERT(IS_SPI_CPOL(config->cpol));
    DEVICE_ASSERT(IS_SPI_CPHA(config->cpha));
    DEVICE_ASSERT(IS_SPI_FRAMESIZE(config->frmSize));

    CKGEN_Enable(g_spiInfo[spiIndex].CKGEN_SPIx, ENABLE);       /* Enable SPI clock */
    CKGEN_SoftReset(g_spiInfo[spiIndex].SRST_SPIx, ENABLE);     /* Reset SPI Module */

    s_spiCallbackArray[spiIndex] = config->callBack;

#ifdef SPI_USE_INTERRUPT_TRANSMIT
    SPI_InitInterruptHandler(SPIx);
#endif

    SPI_SetMode(SPIx, config->mode);

    if (config->interruptEn)
    {
        NVIC_EnableIRQ(g_spiInfo[spiIndex].SPIx_IRQn);
    }
    else
    {
        NVIC_DisableIRQ(g_spiInfo[spiIndex].SPIx_IRQn);
    }

    SPI_SetBaudrate(SPIx, config->sckLow, config->sckHigh);   /* prescale is : low + high + 2 */

    SPI_CSHold(SPIx, config->csHold);
    SPI_CSSetup(SPIx, config->csSetup);
    SPI_SetCSIdle(SPIx, config->csIdle);
    SPI_SetFRMSize(SPIx, config->frmSize);

    SPI_SetDMARxEn(SPIx, config->dmaRxEn);
    SPI_SetDMATxEn(SPIx, config->dmaTxEn);

    SPI_SetCPHA(SPIx, config->cpha);
    SPI_SetCPOL(SPIx, config->cpol);
    SPI_SetTMSBF(SPIx, config->txMsbFirstEn);
    SPI_SetRMSBF(SPIx, config->rxMsbFirstEn);

    SPI_SetCSOE(SPIx, config->csOutputEn);

    SPI_SetContinuousCS(SPIx, config->continuousCSEn);
    SPI_SetModeFault(SPIx, config->modeFaultEn);

    SPI_SetModeFaultInterrupt(SPIx, config->modeFaultInterruptEn);  /* Set spi mode fault detect interrupt */
    SPI_SetTxUInterrupt(SPIx, config->txUFInterruptEn);             /* Set spi tx under flow interrupt */
    SPI_SetRxOInterrupt(SPIx, config->rxOFInterruptEn);             /* Set spi rx over flow interrupt */

    SPI_SetWakeup(SPIx, config->wakeUpEn);

    SPI_SetEnable(SPIx, config->spiEn);
}

/*!
 * @brief Uninitialize SPI module
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @return none
 */
void SPI_DeInit(SPI_Type *SPIx)
{
    SPI_IndexType spiIndex = SPI_INDEX(SPIx);

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    NVIC_DisableIRQ(g_spiInfo[spiIndex].SPIx_IRQn);
    NVIC_ClearPendingIRQ(g_spiInfo[spiIndex].SPIx_IRQn);
    CKGEN_SoftReset(g_spiInfo[spiIndex].SRST_SPIx, DISABLE);
    CKGEN_Enable(g_spiInfo[spiIndex].CKGEN_SPIx, DISABLE);

    s_spiCallbackArray[spiIndex] = NULL;
}

/*!
 * @brief Clear SPI Tx under flow and Rx over flow status
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @return Function status
 *            0: ERROR, Occur Tx under flow or Rx over flow flag
 *            1: SUCCESS, no Tx under flow and Rx over flow flag
 */
static ERROR_Type SPI_ClearTxUFRxOF(SPI_Type *SPIx)
{
    ERROR_Type ret = SUCCESS;

    /* Clear Tx under flow flag */
    if (SPI_IsTxUF(SPIx))
    {
        SPI_ClearTxUF(SPIx);
        ret = ERROR;
    }
    else
    {
        /* Do nothing */
    }

    /* Clear Rx over flow flag */
    if (SPI_IsRxOF(SPIx))
    {
        SPI_ClearRxOF(SPIx);
        ret = ERROR;
    }
    else
    {
        /* Do nothing */
    }

    return ret;
}

/*!
 * @brief SPI transmission,reception by polling
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] rxBuffer: point to the receive data
 * @param[in] txBuffer: point to the send data
 * @param[in] length: transfer data length
 * @return Function status
 *            0: ERROR, length is 0 or rdbuff is NULL or txBuffer is NULL
 *            1: SUCCESS
 */
ERROR_Type SPI_TransmitReceivePoll(SPI_Type *SPIx, uint8_t *rxBuffer, const uint8_t *txBuffer, uint32_t length)
{
    uint32_t  i = 0U;
    ERROR_Type ret = SUCCESS;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    if ((length == 0U) || (rxBuffer == NULL) || (txBuffer == NULL))
    {
        ret = ERROR;
    }
    else
    {
        /* Disable Tx/Rx only mode */
        SPI_SetTxOnly(SPIx, DISABLE);
        SPI_SetRxOnly(SPIx, DISABLE);

        if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* FrameSize is 9 bits ~ 16 bits */
        {
            if (((uint32_t)txBuffer & 0x01U) || ((uint32_t)rxBuffer & 0x01U)) /* txBuffer or rxBufer is not half-word alignment */
            {
                ret = ERROR;
                return ret;
            }

            length = length >> 0x01U;
            /* transmit and receive data */
            for (i = 0U; i < length; i++)
            {
                while (!SPI_IsTxEF(SPIx));
                SPI_WriteDataReg(SPIx, ((uint16_t *)txBuffer)[i]);
                while (!SPI_IsRxFF(SPIx));
                ((uint16_t *)rxBuffer)[i] = SPI_ReadDataReg(SPIx);
            }
        }
        else  /* FrameSize is 4 bits ~ 8 bits */
        {
            /* transmit and receive data */
            for (i = 0U; i < length; i++)
            {
                while (!SPI_IsTxEF(SPIx));
                SPI_WriteDataReg(SPIx, txBuffer[i]);
                while (!SPI_IsRxFF(SPIx));
                rxBuffer[i] = (uint8_t)SPI_ReadDataReg(SPIx);
            }
        }
        while ((SPI_IsBusy(SPIx)));
        SPI_CSRelease(SPIx);
    }

    /* Check and Clear Tx under flow/ Rx over flow flag */
    if (SPI_ClearTxUFRxOF(SPIx) == ERROR)
    {
        ret = ERROR;
    }
    else
    {
        /* Do nothing */
    }

    return ret;
}

/*!
 * @brief SPI transfer by polling, ignore receive (txOnly mode)
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] txBuffer: point to the send data
 * @param[in] length: transfer data length
 * @return Function status
 *            0: ERROR, length is 0 or txBuffer is NULL
 *            1: SUCCESS
 */
ERROR_Type SPI_TransmitPoll(SPI_Type *SPIx, const uint8_t *txBuffer, uint32_t length)
{
    uint32_t  i;
    ERROR_Type ret = SUCCESS;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    if ((length == 0U) || (txBuffer == NULL))
    {
        ret = ERROR;
    }
    else
    {
        SPI_SetTxOnly(SPIx, ENABLE);
        SPI_SetRxOnly(SPIx, DISABLE);

        if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* FrameSize is 9 bits ~ 16 bits */
        {
            if ((uint32_t)txBuffer & 0x01U) /* txBuffer is not half-word alignment */
            {
                ret = ERROR;
                return ret;
            }

            length = length >> 0x01U;
            for (i = 0U; i < length; i++)
            {
                while (!SPI_IsTxEF(SPIx));
                SPI_WriteDataReg(SPIx, ((uint16_t *)txBuffer)[i]);
            }
        }
        else  /* FrameSize is 4 bits ~ 8 bits */
        {
            for (i = 0U; i < length; i++)
            {
                while (!SPI_IsTxEF(SPIx));
                SPI_WriteDataReg(SPIx, txBuffer[i]);
            }
        }
        while ((SPI_IsBusy(SPIx)));
        SPI_CSRelease(SPIx);
    }

    /* Check and Clear Tx under flow/ Rx over flow flag */
    if (SPI_ClearTxUFRxOF(SPIx) == ERROR)
    {
        ret = ERROR;
    }
    else
    {
        /* Do nothing */
    }

    return ret;
}

/*!
 * @brief SPI read by polling, ignore write (rxOnly mode)
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] rxBuffer: point to the receive data
 * @param[in] Length: transfer data length
 * @return Function status
 *            0: ERROR, length is 0 or txBuffer is NULL
 *            1: SUCCESS
 */
ERROR_Type SPI_ReceivePoll(SPI_Type *SPIx, uint8_t *rxBuffer, uint32_t length)
{
    uint32_t i = 0U;
    ERROR_Type ret = SUCCESS;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    if ((length == 0U) || (rxBuffer == NULL))
    {
        ret = ERROR;
    }
    else
    {
        SPI_SetTxOnly(SPIx, DISABLE);
        SPI_SetRxOnly(SPIx, ENABLE);

        /* Master mode receive data */
        if (SPI_IsMaster(SPIx))
        {
            SPI_RxOnlyModeTrig(SPIx);    /* Master rx only mode trriger receive data */
            if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* FrameSize is 9 bits ~ 16 bits */
            {
                if ((uint32_t)rxBuffer & 0x01U) /* rxBufer is not half-word alignment */
                {
                    ret = ERROR;
                    return ret;
                }
                length = length >> 0x01U;
                for (i = 0U; i < length; i++)
                {
                    if (i == (length - 1U))
                    {
                        SPI_SetRxOnly(SPIx, DISABLE);
                    }

                    while ((SPI_IsBusy(SPIx)));
                    while (!SPI_IsRxFF(SPIx));
                    ((uint16_t *)rxBuffer)[i] = SPI_ReadDataReg(SPIx);
                }
            }
            else  /* FrameSize is 4 bits ~ 8 bits */
            {
                for (i = 0U; i < length; i++)
                {
                    if (i == (length - 1U))
                    {
                        SPI_SetRxOnly(SPIx, DISABLE);
                    }

                    while ((SPI_IsBusy(SPIx)));
                    while (!SPI_IsRxFF(SPIx));
                    rxBuffer[i] = (uint8_t)SPI_ReadDataReg(SPIx);
                }
            }
        }
        else /* Slave mode receive data */
        {
            if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* FrameSize is 9 bits ~ 16 bits */
            {
                if ((uint32_t)rxBuffer & 0x01U) /* rxBufer is not half-word alignment */
                {
                    ret = ERROR;
                    return ret;
                }
                length = length >> 0x01U;
                for (i = 0U; i < length; i++)
                {
                    while (!SPI_IsRxFF(SPIx));
                    ((uint16_t *)rxBuffer)[i] = SPI_ReadDataReg(SPIx);
                }
            }
            else  /* FrameSize is 4 bits ~ 8 bits */
            {
                for (i = 0U; i < length; i++)
                {
                    while (!SPI_IsRxFF(SPIx));
                    rxBuffer[i] = (uint8_t)SPI_ReadDataReg(SPIx);
                }
            }
        }
        while ((SPI_IsBusy(SPIx)));
        SPI_CSRelease(SPIx);
    }

    /* Check and Clear Tx under flow/ Rx over flow flag */
    if (SPI_ClearTxUFRxOF(SPIx) == ERROR)
    {
        ret = ERROR;
    }
    else
    {
        /* Do nothing */
    }

    return ret;
}

/*!
 * @brief SPI transmission,reception by DMA
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] txDMAx: tx DMA Channel type pointer,x can be 0 to 3
 * @param[in] rxDMAx: rx DMA Channel type pointer,x can be 0 to 3
 * @param[in] rxBuffer: point to the receive data (Buffer must be 4-byte alignment)
 * @param[in] txBuffer: point to the send data
 * @param[in] length: transfer data(uint8_t) length
 *                    If spi frameSize <= 8 bits, length must be 0~32767, because DMA CHAN_LENGTH is 0~32767
 *                    If spi frameSize > 8 bits, length must be multiple of 2, because DMA CHAN_LENGTH is length/2,
 *                    otherwise the last byte cannot be transmit or receive
 * @param[in] callback: set dma interrupt callback function
 * @return Function status
 *            0: ERROR, length is 0 or rdbuff is NULL or txBuffer is NULL
 *            1: SUCCESS
 */
ERROR_Type SPI_TransmitReceiveDMA(SPI_Type *SPIx, DMA_ChannelType *txDMAx, DMA_ChannelType *rxDMAx,  uint8_t *rxBuffer,
                                  const uint8_t *txBuffer, uint16_t length,  DeviceCallback_Type callback)
{
    ERROR_Type ret = SUCCESS;
    DMA_ConfigType dmaConfig;
    DMA_PeriphType dmaPeriphSelect = DMA_PEPIRH_SPI0_TX;
    DMA_MemByteModeType txMemByteMode = DMA_MEM_BYTE_MODE_4TIME;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));
    DEVICE_ASSERT(IS_DMA_PERIPH(txDMAx));
    DEVICE_ASSERT(IS_DMA_PERIPH(rxDMAx));

    if ((uint32_t)txBuffer & 0x03U) /* txBuffer is not word alignment */
    {
        ret = ERROR;
        return ret;
    }

    SPI_SetTxOnly(SPIx, DISABLE);
    SPI_SetRxOnly(SPIx, DISABLE);

    /* Init DMA Channel */
    dmaConfig.memStartAddr = (uint32_t)&rxBuffer[0U];
    dmaConfig.memEndAddr = dmaConfig.memStartAddr + length;
    dmaConfig.periphStartAddr = (uint32_t)(&(SPIx->DATA));

    switch ((uint32_t)SPIx)  /* Set peripheral id */
    {
    case SPI0_BASE:
        dmaConfig.periphSelect = DMA_PEPIRH_SPI0_RX;
        dmaPeriphSelect = DMA_PEPIRH_SPI0_TX;
        break;

    case SPI1_BASE:
        dmaConfig.periphSelect = DMA_PEPIRH_SPI1_RX;
        dmaPeriphSelect = DMA_PEPIRH_SPI1_TX;
        break;

    default:
        break;
    }

    dmaConfig.channelEn = ENABLE;
    dmaConfig.finishInterruptEn = ENABLE;
    dmaConfig.halfFinishInterruptEn = DISABLE;
    dmaConfig.errorInterruptEn = ENABLE;
    dmaConfig.channelPriority = DMA_PRIORITY_VERY_HIGH;
    dmaConfig.circular = DISABLE;
    dmaConfig.direction = DMA_READ_FROM_PERIPH;
    dmaConfig.MEM2MEM = DISABLE;
    if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* FrameSize is 9 bits ~ 16 bits */
    {
        if ((uint32_t)rxBuffer & 0x01U) /* rxBufer is not half-word alignment */
        {
            ret = ERROR;
            return ret;
        }
        txMemByteMode = DMA_MEM_BYTE_MODE_2TIME;
        dmaConfig.memSize = DMA_MEM_SIZE_16BIT;              /* Peripheral to memory, memorySize */
        dmaConfig.periphSize = DMA_PERIPH_SIZE_16BIT;
        dmaConfig.transferNum = length >> 1U;
    }
    else  /* FrameSize is 4 bits ~ 8 bits */
    {
        txMemByteMode = DMA_MEM_BYTE_MODE_4TIME;
        dmaConfig.memSize = DMA_MEM_SIZE_8BIT;              /* Peripheral to memory, memorySize */
        dmaConfig.periphSize = DMA_PERIPH_SIZE_8BIT;
        dmaConfig.transferNum = length;
    }

    dmaConfig.memByteMode = DMA_MEM_BYTE_MODE_1TIME;
    dmaConfig.memIncrement = ENABLE;
    dmaConfig.periphIncrement = DISABLE;
    dmaConfig.callBack = callback;    /* If you don't use inetrrupt callback function, set callback NULL */

    /* Rx DMA: peiripheral(8 bits/16 bits) -> MEM(8 bits/16 bits) */
    DMA_Init(rxDMAx, &dmaConfig);     /* SPI rx DMA Channel init */

    dmaConfig.memByteMode = txMemByteMode;
    dmaConfig.memStartAddr = (uint32_t)&txBuffer[0U];
    dmaConfig.memEndAddr = dmaConfig.memStartAddr + length;
    dmaConfig.memSize = DMA_MEM_SIZE_32BIT;                /* memory to Peripheral, memorySize */
    dmaConfig.periphSelect = dmaPeriphSelect;
    dmaConfig.direction = DMA_READ_FROM_MEM;

    /* Tx DMA: MEM(32 bit)-> peiripheral(8 bits/16 bits) */
    DMA_Init(txDMAx, &dmaConfig);     /* SPI tx DMA Channel init */

    return ret;
}

/*!
 * @brief SPI transmit by DMA, ignore receive (txOnly mode)
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] txDMAx: tx DMA Channel type pointer,x can be 0 to 3
 * @param[in] txBuffer: point to the send data (Buffer must be 4-byte alignment)
 * @param[in] length: transfer data length
 *                    If spi frameSize <= 8 bits, length must be 0~32767, because DMA CHAN_LENGTH is 0~32767
 *                    If spi frameSize > 8 bits, length must be multiple of 2, because DMA CHAN_LENGTH is length/2,
 *                    otherwise the last byte cannot be transmit or receive
 * @param[in] callback: set dma interrupt callback function
 * @return Function status
 *            0: ERROR, length is 0 or txBuffer is NULL
 *            1: SUCCESS
 */
ERROR_Type SPI_TransmitDMA(SPI_Type *SPIx, DMA_ChannelType *txDMAx, const uint8_t *txBuffer, uint16_t length,
                           DeviceCallback_Type callback)
{
    ERROR_Type ret = SUCCESS;
    DMA_ConfigType dmaConfig;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));
    DEVICE_ASSERT(IS_DMA_PERIPH(txDMAx));

    if ((uint32_t)txBuffer & 0x03U) /* txBuffer is not word alignment */
    {
        ret = ERROR;
        return ret;
    }

    SPI_SetTxOnly(SPIx, ENABLE);
    SPI_SetRxOnly(SPIx, DISABLE);

    /* Init DMA Channel */
    dmaConfig.memStartAddr = (uint32_t)&txBuffer[0U];
    dmaConfig.memEndAddr = dmaConfig.memStartAddr + length;
    dmaConfig.periphStartAddr = (uint32_t)(&(SPIx->DATA));

    switch ((uint32_t)SPIx)  /* Set peripheral id */
    {
    case SPI0_BASE:
        dmaConfig.periphSelect = DMA_PEPIRH_SPI0_TX;
        break;

    case SPI1_BASE:
        dmaConfig.periphSelect = DMA_PEPIRH_SPI1_TX;
        break;

    default:
        break;
    }

    dmaConfig.channelEn = ENABLE;
    dmaConfig.finishInterruptEn = ENABLE;
    dmaConfig.halfFinishInterruptEn = DISABLE;
    dmaConfig.errorInterruptEn = ENABLE;
    dmaConfig.channelPriority = DMA_PRIORITY_VERY_HIGH;
    dmaConfig.circular = DISABLE;
    dmaConfig.direction = DMA_READ_FROM_MEM;
    dmaConfig.MEM2MEM = DISABLE;
    if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* FrameSize is 9 bits ~ 16 bits */
    {
        dmaConfig.memByteMode = DMA_MEM_BYTE_MODE_2TIME;
        dmaConfig.periphSize = DMA_PERIPH_SIZE_16BIT;
        dmaConfig.transferNum = length >> 1U;
    }
    else  /* FrameSize is 4 bits ~ 8 bits */
    {
        dmaConfig.memByteMode = DMA_MEM_BYTE_MODE_4TIME;
        dmaConfig.periphSize = DMA_PERIPH_SIZE_8BIT;
        dmaConfig.transferNum = length;
    }
    dmaConfig.memIncrement = ENABLE;
    dmaConfig.periphIncrement = DISABLE;
    dmaConfig.memSize = DMA_MEM_SIZE_32BIT;
    dmaConfig.callBack = callback;    /* If you don't use inetrrupt callback function, set callback NULL */

    DMA_Init(txDMAx, &dmaConfig);     /* SPI tx DMA Channel init */

    return ret;
}

/*!
 * @brief SPI read by DMA, ignore write (rxOnly mode).
 *        This function must be used by spi slave mode, master mode cannnot used.
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] rxDMAx: rx DMA Channel type pointer,x can be 0 to 3
 * @param[in] rxBuffer: point to the receive data
 * @param[in] length: transfer data length
 *                    If spi frameSize <= 8 bits, length must be 0~32767, because DMA CHAN_LENGTH is 0~32767
 *                    If spi frameSize > 8 bits, length must be multiple of 2, because DMA CHAN_LENGTH is length/2,
 *                    otherwise the last byte cannot be transmit or receive
 * @param[in] callback: set dma interrupt callback function
 * @return Function status
 *            0: ERROR, length is 0 or txBuffer is NULL
 *            1: SUCCESS
 */
ERROR_Type SPI_ReceiveDMA(SPI_Type *SPIx, DMA_ChannelType *rxDMAx, uint8_t *rxBuffer, uint16_t length,
                          DeviceCallback_Type callback)
{
    ERROR_Type ret = SUCCESS;
    DMA_ConfigType dmaConfig;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));
    DEVICE_ASSERT(IS_DMA_PERIPH(rxDMAx));

    SPI_SetTxOnly(SPIx, DISABLE);
    SPI_SetRxOnly(SPIx, ENABLE);

    /* Init DMA Channel */
    dmaConfig.memStartAddr = (uint32_t)&rxBuffer[0U];
    dmaConfig.memEndAddr = dmaConfig.memStartAddr + length;
    dmaConfig.periphStartAddr = (uint32_t)(&(SPIx->DATA));

    switch ((uint32_t)SPIx)  /* Set peripheral id */
    {
    case SPI0_BASE:
        dmaConfig.periphSelect = DMA_PEPIRH_SPI0_RX;
        break;

    case SPI1_BASE:
        dmaConfig.periphSelect = DMA_PEPIRH_SPI1_RX;
        break;

    default:
        break;
    }

    dmaConfig.channelEn = ENABLE;
    dmaConfig.finishInterruptEn = ENABLE;
    dmaConfig.halfFinishInterruptEn = DISABLE;
    dmaConfig.errorInterruptEn = ENABLE;
    dmaConfig.channelPriority = DMA_PRIORITY_VERY_HIGH;
    dmaConfig.circular = DISABLE;
    dmaConfig.direction = DMA_READ_FROM_PERIPH;
    dmaConfig.MEM2MEM = DISABLE;
    if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* FrameSize is 9 bits ~ 16 bits */
    {
        if ((uint32_t)rxBuffer & 0x01) /* rxBufer is not half-word alignment */
        {
            ret = ERROR;
            return ret;
        }
        dmaConfig.memSize = DMA_MEM_SIZE_16BIT;
        dmaConfig.periphSize = DMA_PERIPH_SIZE_16BIT;
        dmaConfig.transferNum = length >> 1U;
    }
    else  /* FrameSize is 4 bits ~ 8 bits */
    {
        dmaConfig.memSize = DMA_MEM_SIZE_8BIT;
        dmaConfig.periphSize = DMA_PERIPH_SIZE_8BIT;
        dmaConfig.transferNum = length;
    }
    dmaConfig.memByteMode = DMA_MEM_BYTE_MODE_1TIME;
    dmaConfig.memIncrement = ENABLE;
    dmaConfig.periphIncrement = DISABLE;
    dmaConfig.callBack = callback;    /* If you don't use inetrrupt callback function, set callback NULL */

    DMA_Init(rxDMAx, &dmaConfig);     /* SPI rx DMA Channel init */

    /* Master rx only mode trriger receive data */
    if (SPI_IsMaster(SPIx))
    {
        SPI_RxOnlyModeTrig(SPIx);
    }
    else
    {
        /* Do nothing */
    }

    return ret;
}

#ifdef SPI_USE_INTERRUPT_TRANSMIT
/*!
 * @brief SPI transmission, reception by interrupt
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] rxBuffer: point to the receive data
 * @param[in] txBuffer: point to the send data
 * @param[in] length: transfer data length
 * @return Function status
 *            0: ERROR, length is 0 or rdbuff is NULL or txBuffer is NULL
 *            1: SUCCESS
 */
ERROR_Type SPI_TransmitReceiveInt(SPI_Type *SPIx, uint8_t *rxBuffer, const uint8_t *txBuffer, uint32_t length)
{
    SPI_IndexType spiIndex = SPI_INDEX(SPIx);

    ERROR_Type ret = SUCCESS;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    if ((length == 0U) || (rxBuffer == NULL) || (txBuffer == NULL))
    {
        ret = ERROR;
    }
    else
    {
        SPI_SetTxOnly(SPIx, DISABLE);
        SPI_SetRxOnly(SPIx, DISABLE);

        if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* FrameSize is 9 bits ~ 16 bits */
        {
            if (((uint32_t)txBuffer & 0x01U) || ((uint32_t)rxBuffer & 0x01U)) /* txBuffer or rxBufer is not half-word alignment */
            {
                ret = ERROR;
                return ret;
            }
            g_spiBuffSize[spiIndex] = length >> 0x01U;
        }
        else   /* FrameSize is 4 bits ~ 8 bits */
        {
            g_spiBuffSize[spiIndex] = length;
        }
        g_spiRxBuf[spiIndex] = rxBuffer;
        g_spiTxBuf[spiIndex] = txBuffer;
        g_spiRxCount[spiIndex] = 0U;
        g_spiTxCount[spiIndex] = 0U;
        g_spiStatus[spiIndex] = SPI_STATUS_NONE;
        SPI_SetRxFInterrupt(SPIx, ENABLE);
        SPI_SetTxEInterrupt(SPIx, ENABLE);
    }

    return ret;
}

/*!
 * @brief SPI transmission by interrupt, ignore reception (txOnly mode)
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] txBuffer: point to the send data
 * @param[in] length: transfer data length
 * @return Function status
 *            0: ERROR, length is 0 or txBuffer is NULL
 *            1: SUCCESS
 */
ERROR_Type SPI_TransmitInt(SPI_Type *SPIx, const uint8_t *txBuffer, uint32_t length)
{
    SPI_IndexType spiIndex = SPI_INDEX(SPIx);

    ERROR_Type ret = SUCCESS;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    if ((length == 0U) || (txBuffer == NULL))
    {
        ret = ERROR;
    }
    else
    {
        SPI_SetTxOnly(SPIx, ENABLE);
        SPI_SetRxOnly(SPIx, DISABLE);

        if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* 9~16 bits frameSize */
        {
            if ((uint32_t)txBuffer & 0x01U) /* txBuffer is not half-word alignment */
            {
                ret = ERROR;
                return ret;
            }
            g_spiBuffSize[spiIndex] = length >> 0x01U;
        }
        else   /* 4~8 bits frameSize */
        {
            g_spiBuffSize[spiIndex] = length;
        }
        g_spiRxBuf[spiIndex] = NULL;
        g_spiTxBuf[spiIndex] = txBuffer;
        g_spiRxCount[spiIndex] = 0U;
        g_spiTxCount[spiIndex] = 0U;
        g_spiStatus[spiIndex] = SPI_STATUS_NONE;
        SPI_SetRxFInterrupt(SPIx, DISABLE);
        SPI_SetTxEInterrupt(SPIx, ENABLE);
    }

    return ret;
}

/*!
 * @brief SPI read by interrupt, ignore write (rxOnly mode)
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] rxBuffer: point to the receive data
 * @param[in] length: transfer data length
 * @return Function status
 *            0: ERROR, length is 0 or txBuffer is NULL
 *            1: SUCCESS
 */
ERROR_Type SPI_ReceiveInt(SPI_Type *SPIx, uint8_t *rxBuffer, uint32_t length)
{
    SPI_IndexType spiIndex = SPI_INDEX(SPIx);
    ERROR_Type ret = SUCCESS;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    if ((length == 0U) || (rxBuffer == NULL))
    {
        ret = ERROR;
    }
    else
    {
        SPI_SetTxOnly(SPIx, DISABLE);
        SPI_SetRxOnly(SPIx, ENABLE);

        if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS)  /* 9~16 bits frameSize */
        {
            if ((uint32_t)rxBuffer & 0x01U) /* rxBufer is not half-word alignment */
            {
                ret = ERROR;
                return ret;
            }
            g_spiBuffSize[spiIndex] = length >> 0x01U;
        }
        else   /* 4~8 bits frameSize */
        {
            g_spiBuffSize[spiIndex] = length;
        }
        g_spiRxBuf[spiIndex] = rxBuffer;
        g_spiTxBuf[spiIndex] = NULL;
        g_spiRxCount[spiIndex] = 0U;
        g_spiTxCount[spiIndex] = 0U;
        g_spiStatus[spiIndex] = SPI_STATUS_NONE;
        SPI_SetTxEInterrupt(SPIx, DISABLE);
        SPI_SetRxFInterrupt(SPIx, ENABLE);

        /* Master rx only mode trriger receive data */
        if (SPI_IsMaster(SPIx))
        {
            SPI_RxOnlyModeTrig(SPIx);
        }
        else
        {
            /* Do nothing */
        }
    }

    return ret;
}

/*!
 * @brief Get SPI interrupt transfer status
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @return SPI transfer status
 *               BIT0: SPI_STATUS_RX_OVERFLOW_MASK  0: No Rx over flow  1: Occur Rx over flow
 *               BIT1: SPI_STATUS_TX_UNDERFLOW_MASK 0: No Tx under flow 1: Occur Tx under flow
 *               BIT2: SPI_STATUS_MODE_FAULT_MASK   0: No Mode fault    1: Occur Mode fault
 *               BIT3: SPI_STATUS_RX_FINISH_MASK    0: Rx by interrupt is not finished    1: Rx by interrupt is finished
 *               BIT4: SPI_STATUS_TX_FINISH_MASK    0: Tx by interrupt is not finished    1: Tx by interrupt is finished
 */
uint32_t SPI_GetTransmitReceiveStatus(SPI_Type *SPIx)
{
    uint8_t  spiIndex = ((uint32_t)SPIx - (uint32_t)SPI0) >> 12U;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    return g_spiStatus[spiIndex];
}

/*!
 * @brief Reset SPI interrupt transfer status
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @return none
 */
void SPI_ResetTransmitReceiveStatus(SPI_Type *SPIx)
{
    uint8_t  spiIndex = ((uint32_t)SPIx - (uint32_t)SPI0) >> 12U;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    g_spiStatus[spiIndex] = SPI_STATUS_NONE;
}

/*!
 * @brief Wait SPI receive(interrupt mode) finish
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @return Function status
 *            0: ERROR, timeout
 *            1: SUCCESS
 */
ERROR_Type SPI_WaitReceiveFinish(SPI_Type *SPIx)
{
    uint32_t timer = 0U;
    ERROR_Type ret = SUCCESS;

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    while (!(SPI_GetTransmitReceiveStatus(SPIx) & SPI_STATUS_RX_FINISH_MASK))
    {
        timer++;
        if (timer > 0xFFFFFFFU)
        {
            SPI_ResetTransmitReceiveStatus(SPIx);
            ret = ERROR;
        }
    }

    SPI_ResetTransmitReceiveStatus(SPIx);

    return ret;
}

#endif /* SPI_USE_INTERRUPT_TRANSMIT */

/*!
 * @brief Release SPI Master CS to stop continuous selection of Slave
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @return none
 */
void SPI_MasterReleaseCS(SPI_Type *SPIx)
{
    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    while ((SPI_IsBusy(SPIx)));
    SPI_CSRelease(SPIx);
}

/*!
 * @brief Set SPI interrupt callback
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @return none
 */
void SPI_SetCallback(SPI_Type *SPIx, const DeviceCallback_Type callback)
{
    SPI_IndexType spiIndex = SPI_INDEX(SPIx);

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    s_spiCallbackArray[spiIndex] = callback;
}

#ifdef SPI_USE_INTERRUPT_TRANSMIT
/*!
 * @brief Initialize SPI interrupt handler
 *
 * @param[in] void
 * @return none
 */
static void SPI_InitInterruptHandler(SPI_Type *SPIx)
{
    SPI_IndexType spiIndex = SPI_INDEX(SPIx);

    if (spiIndex < SPI_INDEX_MAX)
    {
        g_spiRxBuf[spiIndex] = NULL;
        g_spiTxBuf[spiIndex] = NULL;
        g_spiRxCount[spiIndex] = 0U;
        g_spiTxCount[spiIndex] = 0U;
        g_spiStatus[spiIndex] = SPI_STATUS_NONE;
    }
    else
    {
        /* do nothing */
    }
}

/*!
 * @brief SPI handles Tx and Rx in interrupt
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @return none
 */
static void SPI_InterruptHandler(SPI_Type *SPIx)
{
    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    if (SPI_IsMaster(SPIx))
    {
        SPI_MasterInterruptHandler(SPIx);
    }
    else
    {
        SPI_SlaveInterruptHandler(SPIx);
    }
}

/*!
 * @brief Set SPI master callback function
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] wparam: reserved for customers' callback fucntion
 * @param[in] lparam: reserved for customers' callback fucntion
 * @return none
 */
static void SPI_MasterInterruptHandler(SPI_Type *SPIx)
{
    SPI_IndexType spiIndex = SPI_INDEX(SPIx);

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    if (SPI_IsTxUF(SPIx))
    {
        SPI_ClearTxUF(SPIx);
        g_spiStatus[spiIndex] |= SPI_STATUS_TX_UNDERFLOW_MASK;
    }

    if (SPI_IsRxOF(SPIx))
    {
        SPI_ClearRxOF(SPIx);
        g_spiStatus[spiIndex] |= SPI_STATUS_RX_OVERFLOW_MASK;
    }

    while ((SPI_IsBusy(SPIx)));

    if ((SPI_IsRxFF(SPIx)) && (SPI_IsRxFFIE(SPIx)))
    {
        if (g_spiRxCount[spiIndex] < g_spiBuffSize[spiIndex])
        {
            if (g_spiRxBuf[spiIndex] != NULL)
            {
                /* Disable Rx only mode when Receive last data, to avoid next read sck in Rx only mode */
                if (g_spiRxCount[spiIndex] == (g_spiBuffSize[spiIndex] - 1U))
                {
                    SPI_SetRxOnly(SPIx, DISABLE);
                }
                /* Handle Receive data */
                if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS) /* FrameSize is 9 bits ~ 16 bits */
                {
                    ((uint16_t *)g_spiRxBuf[spiIndex])[g_spiRxCount[spiIndex]++] = SPI_ReadDataReg(SPIx);
                }
                else  /* FrameSize is 4 bits ~ 8 bits */
                {
                    g_spiRxBuf[spiIndex][g_spiRxCount[spiIndex]++] = (uint8_t)SPI_ReadDataReg(SPIx);
                }
            }
        }

        if (g_spiRxCount[spiIndex] >= g_spiBuffSize[spiIndex])
        {
            SPI_SetRxFInterrupt(SPIx, DISABLE);
            g_spiStatus[spiIndex] |= SPI_STATUS_RX_FINISH_MASK;
            /* txrx mode or rx only mode cs release */
            SPI_MasterReleaseCS(SPIx);
        }
    }

    if ((SPI_IsTxEF(SPIx)) && (SPI_IsTxEFIE(SPIx)))
    {
        if (g_spiTxCount[spiIndex] < g_spiBuffSize[spiIndex])
        {
            if (g_spiTxBuf[spiIndex] != NULL)
            {
                /* Handle Receive data */
                if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS) /* FrameSize is 9 bits ~ 16 bits */
                {
                    SPI_WriteDataReg(SPIx, ((uint16_t *)g_spiTxBuf[spiIndex])[g_spiTxCount[spiIndex]++]);
                }
                else  /* FrameSize is 4 bits ~ 8 bits */
                {
                    SPI_WriteDataReg(SPIx, g_spiTxBuf[spiIndex][g_spiTxCount[spiIndex]++]);
                }
            }
        }

        if (g_spiTxCount[spiIndex] >= g_spiBuffSize[spiIndex])
        {
            SPI_SetTxEInterrupt(SPIx, DISABLE);
            g_spiStatus[spiIndex] |= SPI_STATUS_TX_FINISH_MASK;

            if (SPIx->CFG2 & SPI_CFG2_TOEN_Msk)
            {
                /* tx only mode cs release */
                SPI_MasterReleaseCS(SPIx);
            }
        }
    }

    if (SPI_IsModeFault(SPIx))
    {
        SPI_SoftwareReset(SPIx);
        g_spiStatus[spiIndex] |= SPI_STATUS_MODE_FAULT_MASK;
    }
}

/*!
 * @brief Set SPI slave callback function
 *
 * @param[in] SPIx: SPI type pointer SPIx, x can be 0 to 1
 * @param[in] wparam: reserved for customers' callback fucntion
 * @param[in] lparam: reserved for customers' callback fucntion
 * @return none
 */
static void SPI_SlaveInterruptHandler(SPI_Type *SPIx)
{
    SPI_IndexType spiIndex = SPI_INDEX(SPIx);

    DEVICE_ASSERT(IS_SPI_PERIPH(SPIx));

    if (SPI_IsTxUF(SPIx))
    {
        SPI_ClearTxUF(SPIx);
        SPI_SetTxEInterrupt(SPIx, DISABLE);
        g_spiStatus[spiIndex] |= SPI_STATUS_TX_UNDERFLOW_MASK;
    }

    if (SPI_IsRxOF(SPIx))
    {
        SPI_ClearRxOF(SPIx);
        SPI_SetRxFInterrupt(SPIx, DISABLE);
        g_spiStatus[spiIndex] |= SPI_STATUS_RX_OVERFLOW_MASK;
    }

    if (SPI_IsRxFF(SPIx))
    {
        if (g_spiRxCount[spiIndex] < g_spiBuffSize[spiIndex])
        {
            if (g_spiRxBuf[spiIndex] != NULL)
            {
                /* Handle Receive data */
                if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS) /* FrameSize is 9 bits ~ 16 bits */
                {
                    ((uint16_t *)g_spiRxBuf[spiIndex])[g_spiRxCount[spiIndex]++] = SPI_ReadDataReg(SPIx);
                }
                else  /* FrameSize is 4 bits ~ 8 bits */
                {
                    g_spiRxBuf[spiIndex][g_spiRxCount[spiIndex]++] = (uint8_t)SPI_ReadDataReg(SPIx);
                }
            }
        }

        if (g_spiRxCount[spiIndex] >= g_spiBuffSize[spiIndex])
        {
            SPI_SetRxFInterrupt(SPIx, DISABLE);
            g_spiStatus[spiIndex] |= SPI_STATUS_RX_FINISH_MASK;
        }
    }

    if (SPI_IsTxEF(SPIx))
    {
        if (g_spiTxCount[spiIndex] < g_spiBuffSize[spiIndex])
        {
            if (g_spiTxBuf[spiIndex] != NULL)
            {
                /* Handle Receive data */
                if ((SPI_FrameSizeType)SPI_GetFRMSize(SPIx) > SPI_FRAME_SIZE_8BITS) /* FrameSize is 9 bits ~ 16 bits */
                {
                    SPI_WriteDataReg(SPIx, ((uint16_t *)g_spiTxBuf[spiIndex])[g_spiTxCount[spiIndex]++]);
                }
                else  /* FrameSize is 4 bits ~ 8 bits */
                {
                    SPI_WriteDataReg(SPIx, g_spiTxBuf[spiIndex][g_spiTxCount[spiIndex]++]);
                }
            }
        }

        else if (g_spiTxCount[spiIndex] >= g_spiBuffSize[spiIndex])
        {
            SPI_SetTxEInterrupt(SPIx, DISABLE);
            g_spiStatus[spiIndex] |= SPI_STATUS_TX_FINISH_MASK;
        }
    }
}
#endif /* SPI_USE_INTERRUPT_TRANSMIT */

/*!
 * @brief override the SPI0_IRQHandler
 *
 * @param[in] none
 * @return none
 */
void SPI0_IRQHandler(void)
{
    uint32_t statusReg = SPI0->STATUS;
    uint32_t cfg1Reg = SPI0->CFG1;

#ifdef SPI_USE_INTERRUPT_TRANSMIT
    SPI_InterruptHandler(SPI0);
#endif

    if (s_spiCallbackArray[SPI0_INDEX])
    {
        s_spiCallbackArray[SPI0_INDEX](SPI0, statusReg, cfg1Reg);
    }
}

/*!
 * @brief override the SPI1_IRQHandler
 *
 * @param[in] none
 * @return none
 */
void SPI1_IRQHandler(void)
{
    uint32_t statusReg = SPI1->STATUS;
    uint32_t cfg1Reg = SPI1->CFG1;

#ifdef SPI_USE_INTERRUPT_TRANSMIT
    SPI_InterruptHandler(SPI1);
#endif

    if (s_spiCallbackArray[SPI1_INDEX])
    {
        s_spiCallbackArray[SPI1_INDEX](SPI1, statusReg, cfg1Reg);
    }
}

/* =============================================  EOF  ============================================== */
